package com.wzw.basics.concurrent.thread;

import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程池
 * <p>
 * execute() : 接收Runnable对象，线程执行完成后无返回值，线程内方法异常时会抛出异常，打印异常信息
 * submit() : 接收Runnable或者Callable对象，线程执行完成后可以获取返回值，线程内方法异常时，不会抛出异常只有显示调用get方法获取结果时才会抛出异常
 * Runnable与Callable对象都能获取到线程执行的结果，原理时内部会通过newTaskFor方法将其在包装成FutureTask
 */
public class ThreadPool {
    public static class ThreadNames {
        public static final String TEST = "Test";
    }

    static class DefaultThreadPoolParams {
        public static final int coreSize = Runtime.getRuntime().availableProcessors() + 1;
        public static final int maximumPoolSize = Runtime.getRuntime().availableProcessors() * 5;
        public static final long keepAliveTime = 60;
        public static final TimeUnit unit = TimeUnit.SECONDS;
        public static final BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(120);
        public static final RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
    }

    static class MyThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        MyThreadFactory(String poolName) {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            namePrefix = poolName + "-" + poolNumber.getAndIncrement() + "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
            if (t.isDaemon()) {
                t.setDaemon(false);
            }
            if (t.getPriority() != Thread.NORM_PRIORITY) {
                t.setPriority(Thread.NORM_PRIORITY);
            }
            return t;
        }
    }

    private static final Map<String, ThreadPoolExecutor> THREAD_POOL_EXECUTOR_MAP = new ConcurrentHashMap<>(16);

    public static ThreadPoolExecutor defaultParamsPoolExecutor(String poolName) {
        return poolExecutor(poolName, DefaultThreadPoolParams.coreSize, DefaultThreadPoolParams.maximumPoolSize, DefaultThreadPoolParams.keepAliveTime, DefaultThreadPoolParams.unit, DefaultThreadPoolParams.workQueue, DefaultThreadPoolParams.handler);
    }

    public static ThreadPoolExecutor poolExecutor(String poolName, int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        if (THREAD_POOL_EXECUTOR_MAP.containsKey(poolName)) {
            return THREAD_POOL_EXECUTOR_MAP.get(poolName);
        }
        MyThreadFactory factory = new MyThreadFactory(poolName);
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, factory, handler);
        THREAD_POOL_EXECUTOR_MAP.put(poolName, executor);
        return executor;
    }
}
